package com.liaoyifan.core.valid;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import java.util.Set;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

@SuppressWarnings("unused")
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Validation {

    // 快速失败验证器（遇到第一个错误即停止）
    public static final LocalValidatorFactoryBean FAST_VALIDATOR = validator(true);
    // 全量验证器（校验所有错误）
    public static final LocalValidatorFactoryBean ALL_VALIDATOR = validator(false);

    public static <T> void all(T object, Class<?>... groups) {
        valid(ALL_VALIDATOR, object, groups);
    }

    public static <T> void all(T object, String property, Class<?>... groups) {
        valid(ALL_VALIDATOR, object, property, groups);
    }

    public static <T> void all(
            Class<T> clazz, String methodDotField, Object value, Class<?>... groups) {
        valid(ALL_VALIDATOR, clazz, methodDotField, value, groups);
    }

    public static <T> void fast(T object, Class<?>... groups) {
        valid(FAST_VALIDATOR, object, groups);
    }

    public static <T> void fast(T object, String property, Class<?>... groups) {
        valid(FAST_VALIDATOR, object, property, groups);
    }

    public static <T> void fast(
            Class<T> clazz, String methodDotField, Object value, Class<?>... groups) {
        valid(FAST_VALIDATOR, clazz, methodDotField, value, groups);
    }

    private static <T> void valid(
            LocalValidatorFactoryBean validator, T object, Class<?>... groups) {
        Set<ConstraintViolation<T>> violations = validator.getValidator().validate(object, groups);
        if (!violations.isEmpty()) {
            throw new ConstraintViolationException(violations);
        }
    }

    private static <T> void valid(
            LocalValidatorFactoryBean validator, T object, String property, Class<?>... groups) {
        Set<ConstraintViolation<T>> violations =
                validator.getValidator().validateProperty(object, property, groups);
        if (!violations.isEmpty()) {
            throw new ConstraintViolationException(violations);
        }
    }

    private static <T> void valid(
            LocalValidatorFactoryBean validator,
            Class<T> clazz,
            String methodDotField,
            Object value,
            Class<?>... groups) {
        Set<ConstraintViolation<T>> violations =
                validator.getValidator().validateValue(clazz, methodDotField, value, groups);
        if (!violations.isEmpty()) {
            throw new ConstraintViolationException(violations);
        }
    }

    private static LocalValidatorFactoryBean validator(boolean failFast) {
        LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
        validator.setValidationMessageSource(Message.MESSAGE_SOURCE);
        validator
                .getValidationPropertyMap()
                .put("hibernate.validator.fail_fast", String.valueOf(failFast));
        validator.afterPropertiesSet();
        return validator;
    }
}
